package com.example.netty.NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author liupk
 * @date 2018/10/23
 */
public class NIOServer {
    public static void main(String[] args) throws Exception {
        Selector serverSelector = Selector.open();
        Selector clientSelector = Selector.open();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(()->{
            try {
                /**对应IO编程中服务端启动*/
                ServerSocketChannel listenerChannel = ServerSocketChannel.open();
                /**服务器端启动 ServerSocket*/
                listenerChannel.socket().bind(new InetSocketAddress(8000));
                listenerChannel.configureBlocking(false);
                /**调用 accept 方法，阻塞等待客户端连接。*/
                listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
                /**循环监听是否有新连接*/
                while (true) {
                    // 监测是否有新的连接，这里的1指的是阻塞的时间为 1ms
                    if (serverSelector.select(1) > 0) {
                        Set<SelectionKey> set = serverSelector.selectedKeys();
                        Iterator<SelectionKey> keyIterator = set.iterator();
                
                        while (keyIterator.hasNext()) {
                            SelectionKey key = keyIterator.next();
                    
                            if (key.isAcceptable()) {try {
                                /**每来一个新连接，不需要创建一个线程，而是直接注册到clientSelector*/
                                SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                                clientChannel.configureBlocking(false);
                                clientChannel.register(clientSelector, SelectionKey.OP_READ);
                            } finally {
                                keyIterator.remove();
                            }
                            }
                    
                        }
                    }
                }
            } catch (IOException ignored) {
            }
        });
    
        executorService.execute(()->{
            try {
                while (true) {
                    /**(2) 批量轮询是否有哪些连接有数据可读，这里的1指的是阻塞的时间为 1ms*/
                    if (clientSelector.select(1) > 0) {
                        Set<SelectionKey> set = clientSelector.selectedKeys();
                        Iterator<SelectionKey> keyIterator = set.iterator();
                
                        while (keyIterator.hasNext()) {
                            SelectionKey key = keyIterator.next();
                            if (key.isReadable()) {
                                try {
                                    SocketChannel clientChannel = (SocketChannel) key.channel();
                                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                                    // (3) 面向 Buffer
                                    clientChannel.read(byteBuffer);
                                    byteBuffer.flip();
                                    System.out.println(Charset.defaultCharset().newDecoder().decode(byteBuffer)
                                            .toString());
                                } finally {
                                    keyIterator.remove();
                                    key.interestOps(SelectionKey.OP_READ);
                                }
                            }
                    
                        }
                    }
                }
            } catch (IOException ignored) {
            }
        });

    }
}